<template>
  <ComboBox
    v-if="formItem.interaction?.type === ArkInteractionType.SELECT"
    placeholder="请选择"
    textField="text"
    v-model="model[formItem.prop]"
    :data="optionData"
    :disabled="disabled()"
    v-bind="vBindObject"
    v-on="vOnObject"
  ></ComboBox>

  <ComboTree
    v-else-if="formItem.interaction?.type === ArkInteractionType.SELECT_TREE"
    ref="comboTreeRef"
    placeholder="请选择"
    valueField="value"
    v-model="model[formItem.prop]"
    :data="optionData"
    :disabled="disabled()"
    v-bind="vBindObject"
    v-on="vOnObject"
  >
    <template v-slot:tree>
      <Tree
        @nodeExpand="onNodeExpand"
        v-bind="formItem.interaction?.treeAttributes ? formItem.interaction.treeAttributes : {}"
        v-on="formItem.interaction?.treeEvents ? formItem.interaction.treeEvents : {}"
      >
        <template v-slot:icon="{ node }">
          <ArkIconFont
            v-if="node.iconCls"
            class="text-gary2"
            :icon="node.iconCls"
          />

          <span
            v-else
            class="tree-icon tree-folder"
            :class="{
              'tree-file': !node.state,
            }"
          ></span>
        </template>

        <template v-slot="{ node }">
          {{ node.text }}
        </template>
      </Tree>
    </template>
  </ComboTree>

  <div v-else-if="formItem.interaction?.type === ArkInteractionType.RADIO">
    <div v-for="option of formItem.interaction.options" :key="option.text">
      <RadioButton
        v-model="model[formItem.prop]"
        :disabled="disabled()"
        :inputId="option.value"
        :value="option.value"
      ></RadioButton>
      <Label class="!ml-1" :for="option.value">{{ option.text }}</Label>
    </div>
  </div>

  <DateBox
    v-else-if="formItem.interaction?.type === ArkInteractionType.DATE"
    v-model="timeModel"
    :format="timeShowFormat ? timeShowFormat : 'yyyy/MM/dd'"
    :disabled="disabled()"
    v-bind="vBindObject"
    v-on="vOnObject"
  ></DateBox>

  <NumberBox
    v-else-if="formItem.interaction?.type === ArkInteractionType.NUMBER"
    v-model="model[formItem.prop]"
    :disabled="disabled()"
    :precision="formItem.interaction?.precision !== undefined? formItem.interaction?.precision : null"
    :max="formItem.interaction?.max !== undefined ? formItem.interaction?.max : null"
    :min="formItem.interaction?.min !== undefined ? formItem.interaction?.min : null"
    :increment="formItem.interaction?.step !== undefined ? formItem.interaction?.step : 1"
  ></NumberBox>

  <span
    v-else-if="formItem.interaction?.type === ArkInteractionType.READONLY_TEXT"
  >
    {{
      formItem.interaction?.transform
        ? formItem.interaction.transform(model[formItem.prop])
        : model[formItem.prop]
    }}
  </span>

  <TextBox
    v-else
    ref="textBox"
    placeholder="请输入"
    v-model="model[formItem.prop]"
    :disabled="disabled()"
    :multiline="formItem.interaction?.type === ArkInteractionType.TEXT_AREA"
    v-bind="vBindObject"
    v-on="vOnObject"
  ></TextBox>
</template>

<script setup lang="ts">
import {computed, nextTick, onBeforeMount, onMounted, PropType, ref, useTemplateRef, watch,} from "vue";
import _ from "lodash";
import $ from "jquery";
import dayjs from "dayjs";
import {ArkFormInteractionExpose, FormItem, Option} from "./ArkFormOptions";
import ArkInteractionType from "../../common-type/ark-interaction-type";
import ArkIconFont from "../../basic/ark-iconfont/ArkIconFont.vue";

/** 组合（向选项里合并 property）。包括：provide、inject、extends、mixins */

/** 接口（组件的接口）。包括：defineOptions、defineModel、defineProps、defineEmits、defineExpose、defineSlots */
const props = defineProps({
  formItem: {
    type: Object as PropType<FormItem>,
    required: true,
  },
});

const model = defineModel({
  type: Object as PropType<Record<string, any>>,
  required: true,
});

defineExpose<ArkFormInteractionExpose>({
  fetchOptions() {
    return handleSelectType();
  },
});

/** 本地状态 (本地的响应式 property)。包括：ref、computed */
// v-bind、v-on参数
const vBindObject = computed(() => {
  return _.isNil(props.formItem.interaction?.attributes)
    ? {}
    : props.formItem.interaction?.attributes;
});
const vOnObject = computed(() => {
  return _.isNil(props.formItem.interaction?.events)
    ? {}
    : props.formItem.interaction?.events;
});

// 控件类型判断
const isTimeType = computed(() => {
  const interaction = props.formItem.interaction;
  return [ArkInteractionType.DATE].includes(interaction?.type);
});
const isSelectType = computed(() => {
  const interaction = props.formItem.interaction;
  return [
    ArkInteractionType.RADIO,
    ArkInteractionType.SELECT,
    ArkInteractionType.SELECT_TREE,
  ].includes(interaction?.type);
});
const isTextareaType = computed(() => {
  const interaction = props.formItem.interaction;
  return [ArkInteractionType.TEXT_AREA].includes(interaction?.type);
});

// 模版引用
const comboTreeRef = useTemplateRef("comboTreeRef");
const textBoxRef = useTemplateRef("textBox");

// 生命周期判断状态
const mounted = ref(false);

// 选择控件所需状态
const optionData = ref([]);

// 时间控件所需状态
const timeModel = ref<Date | null>(null);
const timeShowFormat = ref(null);

/** 事件（通过响应式事件触发的回调）。包括：watch */
watch(
  () => {
    return props.formItem.interaction?.rows;
  },
  () => {
    handleTextAreaType();
  },
);

// 由于EasyUI时间控件不支持Dayjs格式，因此需内外转换同步
watch(
  () => {
    return timeModel.value;
  },
  () => {
    if (!isTimeType.value) {
      return;
    }

    const interaction = props.formItem.interaction;
    if (interaction?.valueFormat && timeModel.value) {
      model.value[props.formItem.prop] = dayjs(timeModel.value).format(
        interaction.valueFormat,
      );
      return;
    }

    model.value[props.formItem.prop] = timeModel.value;
  },
);
watch(
  () => {
    return model.value[props.formItem.prop];
  },
  () => {
    if (!isTimeType.value) {
      return;
    }

    const interaction = props.formItem.interaction;
    if (interaction?.valueFormat && model.value[props.formItem.prop]) {
      timeModel.value = dayjs(model.value[props.formItem.prop]).toDate();
      return;
    }

    timeModel.value = model.value[props.formItem.prop];
  },
);

/** 生命周期钩子（按照它们被调用的顺序）。包括：onBeforeMount、onMounted、onBeforeUpdate、onUpdated、onBeforeUnmount、onUnmounted */
onBeforeMount(() => {
  init();
});

onMounted(() => {
  mounted.value = true;
  handleTextAreaType();
});

/** 非响应式的 property (不依赖响应系统的实例 property)。包括：常规函数 */
const init = () => {
  handleSelectType();
  handleTimeType();
};
const handleSelectType = async () => {
  if (!isSelectType.value) {
    return;
  }

  const interaction = props.formItem.interaction;
  if (_.isNil(interaction?.options)) {
    return;
  }

  if (Array.isArray(interaction?.options)) {
    optionData.value = interaction.options;
    return;
  }

  if (
    !_.isNil(interaction?.manualFetchOptions) &&
    interaction?.manualFetchOptions
  ) {
    return;
  }

  const optionReturnVal = interaction.options(props.formItem);

  if (Array.isArray(optionReturnVal)) {
    optionData.value = optionReturnVal;
    // ComboTree动态选项存在值延迟渲染问题，在得到异步选项后强制更新显示
    nextTick(() => {
      comboTreeRef?.value?.updateText();
    });
    return;
  }

  Promise.resolve(optionReturnVal).then((options) => {
    const extraAllOptionForAsync =
      props.formItem.interaction?.extraAllOptionForAsync;
    if (_.isNil(extraAllOptionForAsync) || !extraAllOptionForAsync) {
      optionData.value = options;
      nextTick(() => {
        comboTreeRef?.value?.updateText();
      });
      return;
    }

    let allOption: Option;
    if (typeof extraAllOptionForAsync === "boolean") {
      allOption = {
        text: "全部",
        value: "",
      };
    } else {
      allOption = extraAllOptionForAsync;
    }
    options.unshift(allOption);

    optionData.value = options;
    nextTick(() => {
      comboTreeRef?.value?.updateText();
    });
  });
};
const handleTimeType = () => {
  if (!isTimeType.value) {
    return;
  }

  const interaction = props.formItem.interaction;
  // 将输入的dayjs 显示格式与值格式转换为内部组件支持的format
  if (interaction?.showFormat) {
    timeShowFormat.value = interaction.showFormat
      .replaceAll("Y", "y")
      .replaceAll("D", "d");
  }

  if (interaction?.valueFormat && model.value[props.formItem.prop]) {
    timeModel.value = dayjs(
      model.value[props.formItem.prop],
      interaction.valueFormat,
    ).toDate();
  }
};
const handleTextAreaType = () => {
  if (!isTextareaType.value) {
    return;
  }

  const rows = _.isNil(props.formItem.interaction?.rows)
    ? 5
    : props.formItem.interaction.rows;
  const el = textBoxRef.value.$el;
  const textarea = el.querySelector("textarea");

  textarea.setAttribute("rows", rows);
  $(textarea).css("height", "max-content");
  $(el).css("height", $(textarea).css("height"));
};

const disabled = () => {
  if (_.isNil(props.formItem.disabled)) {
    return false;
  }

  if (typeof props.formItem.disabled === "boolean") {
    return props.formItem.disabled;
  }

  return props.formItem.disabled(model.value);
}

const onNodeExpand = (node) => {
  if (props.formItem.interaction?.onNodeExpand) {
    props.formItem.interaction?.onNodeExpand(node);
  }
};

/** 其它 */
</script>

<style scoped lang="scss"></style>
